//
// Unihan Input Method
//
// Copyright © 2002-2007 Sun Wah Linux Ltd.
//
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
// USA
//
// $Id: shuangpin.c 757 2007-05-10 08:19:31Z roger $
//

#include <stdio.h>
#include <string.h>
#include <unihan_im.h>

#include "table.h"
#include "const.h"
#include "shuangpin.h"
#include "cands_factory.h"
#include "aux.h"

static int explore_candidates(UnihanIM *uim, char *cell);

static const SPTable sp_table = {
	{a,	NULL,	"a",	NULL},
	{b,	"b",	"ou",	NULL},
	{c,	"c",	"iao",	NULL},
	{d,	"d",	"uang",	"iang"},
	{e,	NULL,	"e",	NULL},
	{f,	"f",	"en",	NULL},
	{g,	"g",	"eng",	NULL},
	{h,	"h",	"ang",	NULL},
	{i,	"ch",	"i",	NULL},
	{j,	"j",	"an",	NULL},
	{k,	"k",	"ao",	NULL},
	{l,	"l",	"ai",	NULL},
	{m,	"m",	"ian",	NULL},
	{n,	"n",	"in",	NULL},
	{o,	".",	"o",	"uo"},
	{p,	"p",	"un",	NULL},
	{q,	"q",	"iu",	NULL},
	{r,	"r",	"uan",	"er"},
	{s,	"s",	"ong",	"iong"},
	{t,	"t",	"ue",	NULL},
	{u,	"sh",	"u",	NULL},
	{v,	"zh",	"ui",	"ue"},
	{w,	"w",	"ia",	"ua"},
	{x,	"x",	"ie",	NULL},
	{y,	"y",	"uai",	"v"},
	{z,	"z",	"ei",	NULL},
	{;,	NULL,	"ing",	NULL}
};

//static SPFlag sp_flag = SHENGMU;

/* FS : First or Second yunmu */
/* SM_ZERO when return 1      */
char *
SP_get_cell(UnihanIM *uim, IMKeyEvent *kev)
{
	int i;
	TableDataPerDesktop *dd = (TableDataPerDesktop *)uim->desktopUserData;
	TableDataPerSession *ds = (TableDataPerSession *)uim->sessionUserData;
	CandFactory *candFactory = ds->candFactory;
	SPTable *spTable = dd->spTable;

	for (i=0; i<SP_TABLE_MAX_LEN; i++) {
		if (kev->keyChar == spTable[0][i].keyname) {
			if (candFactory->spFlag == SHENGMU) {
				if (spTable[0][i].sheng == NULL) {
					uim->m->beep(uim);
					return NULL;
				}

				if (!explore_candidates(uim, spTable[0][i].sheng)) {
					uim->m->beep(uim);
					return NULL;
				}
				candFactory->spFlag = YUNMU;
				return spTable[0][i].sheng;
			}
			else { //sp_flag == YUNMU
				if (spTable[0][i].yun1) {
					if (!explore_candidates(uim, spTable[0][i].yun1)) {
						if (spTable[0][i].yun2) {
							if (!explore_candidates(uim,
										spTable[0][i].yun2))
							{
								uim->m->beep(uim);
								return NULL;
							} else {
								return spTable[0][i].yun2;
							}
						} else {
							uim->m->beep(uim);
							return NULL;
						}
					} else {
						return spTable[0][i].yun1;
					}
				} else {
					uim->m->beep(uim);
					return NULL;
				}
				candFactory->spFlag = SHENGMU;
			}
		}
	}
	return NULL;
}
 

 
 

 
 
 

 
 
 

}

static int
explore_candidates(UnihanIM *uim, char *cell)
{
	TableDataPerDesktop *dd = (TableDataPerDesktop *)uim->desktopUserData;
	TableDataPerSession *ds = (TableDataPerSession *)uim->sessionUserData;
	CandFactory *candFactory = ds->candFactory;
	MultiCandPos *mcp = candFactory->multiCandPos;
	int low, high, exactIdx, i;
	KeyValTab *kv = NULL;
	char preedit[PREEDIT_LEN_MAX];
	int preeditLen = 0;
	int highIdx, lowIdx, numExactCands, numCands;

	candFactory->numTotalCands = 0;

	/* explore user define word */
	if (mcp->preeditLen) {
		strcpy(preedit, mcp->preedit);
		strcat(preedit, cell);
	} else {
		strcpy(preedit, cell);
	}
	if (get_exact_word2(uim, preedit))
		return TRUE;

	while (mcp) {
		if (mcp->preeditLen) {
			strcpy(preedit, mcp->preedit);
			strcat(preedit, cell);
		} else {
			strcpy(preedit, cell);
		}
		preeditLen = strlen(preedit);

		low = dd->fastIdx[idx(preedit[0])].offset;
		high = dd->fastIdx[idx(preedit[0])+1].offset - 1;
        	i = (low + high)/2;

		// binary search
		if (preeditLen != 1) {
			while (preeditLen > 1) {
				int cmp;

				if (high < low) {
					numExactCands = highIdx =
						lowIdx = exactIdx = -1;
					numCands = 0;
					break;
				}

				i = (low + high)/2;

				kv = &(dd->kvtab[i]);
				cmp = strncmp(preedit + 1,
					dd->keyList+(kv->keyOff) + 1,
					preeditLen-1);
				if (cmp < 0)
					high = i - 1;
				else if (cmp > 0)
					low = i + 1;
				else // cmp == 0!!! found!
					return TRUE;
			}
		}

		// find the real upper and lower ranges
		low = i - 1;
		high = i + 1;
		while (low >= 0) {
			KeyValTab *kv1 = &(dd->kvtab[low]);
			int cmp = strncmp(preedit,
					dd->keyList+(kv1->keyOff),
					preeditLen);
			if (cmp != 0) // found start of range
				break;
			--low;
		}
		++low;
		while (high < dd->numVal) {
			KeyValTab *kv1 = &(dd->kvtab[high]);
			int cmp = strncmp(preedit,
					dd->keyList+(kv1->keyOff),
					preeditLen);
			if (cmp != 0)
				break;
			++high;
		}

		// find how many are exact matches
		kv = &(dd->kvtab[low]);
		if (preeditLen < strlen(dd->keyList + kv->keyOff)) {
			exactIdx = low + 1;
		} else {
			exactIdx = low + 1;
			while (exactIdx < high) {
				kv = &(dd->kvtab[exactIdx]);
				if (*(dd->keyList + kv->keyOff + preeditLen) != 0)
					break;
				++exactIdx;
			}
		}

		lowIdx = low;
		highIdx = high;
		numExactCands = exactIdx - low;
		if (dd->hints & SHOW_AS_U_GO)
			numCands = high - low;
		else
			numCands = mcp->numExactCands;
		mcp = mcp->next;
	}

	if (numCands > 0)
		return TRUE;
	else
		return FALSE;
}

void
SP_append_cell(UnihanIM *uim, char *cell)
{
	TableDataPerSession *ds = (TableDataPerSession *)uim->sessionUserData;
	SP_InputCell *ic = ds->spIC;

	if (!ic) {
		ds->spIC = ic = (SP_InputCell *)malloc(sizeof(SP_InputCell));
		memset(ic, 0, sizeof(SP_InputCell));
		ic->cell = strdup(cell);
		return;
	}

	while (ic->next)
		ic = ic->next;

	ic->next = (SP_InputCell *)malloc(sizeof(SP_InputCell));
	memset(ic, 0, sizeof(SP_InputCell));
	ic->next->prev = ic;
	ic = ic->next;
	ic->cell = strdup(cell);
	return;
}

void
SP_throw_a_cell(UnihanIM *uim)
{
	TableDataPerSession *ds = (TableDataPerSession *)uim->sessionUserData;
	SP_InputCell *ic = ds->spIC;

	if (!ic)
		return;

	while (ic->next)
		ic = ic->next;

	ic = ic->prev;
	free(ic->next);
	ic->next = NULL;
	return;
}

char *
SP_get_the_last_cell(UnihanIM *uim)
{
	TableDataPerSession *ds = (TableDataPerSession *)uim->sessionUserData;
	SP_InputCell *ic = ds->spIC;

	if (!ic)
		return NULL;

	while(ic->next)
		ic = ic->next;

	return ic->cell;
}

// vi:ts=4:nowrap:cin:expandtab
